package com.clp.protocol.modbus_tcp.mb_frame;

import com.clp.protocol.modbus_tcp.definition.*;
import com.clp.protocol.modbus_tcp.mb_frame.mb_body.ReqMbBody;
import com.clp.protocol.modbus_tcp.mb_frame.mb_body.mb_data.ReqMbData;
import com.clp.protocol.modbus_tcp.mb_frame.mb_body.mb_data.req.*;
import com.clp.protocol.modbus_tcp.mb_frame.mb_head.MbHead;
import io.netty.buffer.ByteBuf;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

@Slf4j
public class MbFrmFactory {

    /**
     * 构建请求帧
     * @param seq 序列号
     * @param addr 地址
     * @param funcCode 功能码
     * @param reqMbData 请求数据
     * @return 请求帧
     */
    public static ReqMbFrm getReqMbFrm(int seq, int addr, FuncCode funcCode, ReqMbData reqMbData) {
        MbHead mbHead = new MbHead(seq, Tag.MODBUS_TCP, 0);
        ReqMbBody reqMbBody = new ReqMbBody(addr, funcCode, reqMbData);
        // 构建帧
        return new ReqMbFrm(mbHead, reqMbBody);
    }

    private static boolean isRespOkMbFrmOfByteBuf(ByteBuf buf) {
        byte by = buf.getByte(buf.readerIndex() + ConstVal.MB_HEAD_LEN + ConstVal.ADDR_LEN);
        return (by & 0x80) != 0x80;
    }

    public static RespMbFrm getRespMbFrm(ByteBuf buf) {
        if (isRespOkMbFrmOfByteBuf(buf)) {
            return new RespOkMbFrm().initBy(buf);
        }
        return new RespErrMbFrm().initBy(buf);
    }

    /**
     * 构建请求格式帧 - 读线圈状态
     *
     * @param seq：序列号
     * @param addr：从站地址
     * @param startAddr：数据起始地址
     * @param num：数量
     * @return
     */
    public static ReqMbFrm getReqMbFrmOfReadCoilStatus(int seq, int addr, int startAddr, int num) {
        FuncCode funcCode = FuncCode.READ_COIL_STATUS;
        ReqMbData reqMbData = new ReadCoilStatusReqMbData(startAddr, num);
        return getReqMbFrm(seq, addr, funcCode, reqMbData);
    }

    /**
     * 构建请求格式帧 - 读开关量输入
     *
     * @param seq：序列号
     * @param addr：从站地址
     * @param startAddr：起始地址
     * @param num：数量
     * @return
     */
    public static ReqMbFrm getReqMbFrmOfReadInputStatus(int seq, int addr, int startAddr, int num) {
        FuncCode funcCode = FuncCode.READ_INPUT_STATUS;
        ReqMbData reqMbData = new ReadInputStatusReqMbData(startAddr, num);
        return getReqMbFrm(seq, addr, funcCode, reqMbData);
    }

    /**
     * 构建请求格式帧 - 读保持型寄存器
     *
     * @param seq：序列号
     * @param addr：从站地址
     * @param startAddr：起始地址
     * @param num：读取数量
     * @return
     */
    public static ReqMbFrm getReqMbFrmOfReadHoldRegs(int seq, int addr, int startAddr, int num) {
        FuncCode funcCode = FuncCode.READ_HOLDING_REGISTERS;
        ReqMbData reqMbData = new ReadHoldRegsReqMbData(startAddr, num);
        return getReqMbFrm(seq, addr, funcCode, reqMbData);
    }

    /**
     * 构建请求格式帧 - 读输入型寄存器
     *
     * @param seq：序列号
     * @param addr：从站地址
     * @param startAddr：数据起始地址
     * @param num：读取数量
     * @return
     */
    public static ReqMbFrm getReqMbFrmOfReadInputRegs(int seq, int addr, int startAddr, int num) {
        FuncCode funcCode = FuncCode.READ_INPUT_REGISTERS;
        ReqMbData reqMbData = new ReadInputRegsReqMbData(startAddr, num);
        return getReqMbFrm(seq, addr, funcCode, reqMbData);
    }

    /**
     * 构建请求格式帧 - 设置单个继电器
     *
     * @param seq：序列号
     * @param addr：从站地址
     * @param setAddr：设置地址
     * @param coilSetting：设置内容
     * @return
     */
    public static ReqMbFrm getReqMbFrmOfForceSingleCoil(int seq, int addr, int setAddr, CoilSetting coilSetting) {
        FuncCode funcCode = FuncCode.FORCE_SINGLE_COIL;
        ReqMbData reqMbData = new ForceSingleCoilReqMbData(setAddr, coilSetting);
        return getReqMbFrm(seq, addr, funcCode, reqMbData);
    }

    /**
     * 构建请求格式帧 - 写单个寄存器
     *
     * @param seq：序列号
     * @param addr：从站地址
     * @param setAddr：设置地址
     * @param setVal：设置内容
     * @return
     */
    public static ReqMbFrm getReqMbFrmOfPresetSingleReg(int seq, int addr, int setAddr, int setVal) {
        FuncCode funcCode = FuncCode.PRESET_SINGLE_REGISTER;
        ReqMbData reqMbData = new PresetSingleRegReqMbData(setAddr, setVal);
        return getReqMbFrm(seq, addr, funcCode, reqMbData);
    }

    /**
     * 构建请求格式帧 - 设置多个继电器
     *
     * @param seq：序列号
     * @param addr：从站地址
     * @param startAddr：起始地址
     * @param coilStatuses：线圈状态列表
     * @return
     */
    public static ReqMbFrm getReqMbFrmOfForceMultiCoils(int seq, int addr, int startAddr, List<CoilStatus> coilStatuses) {
        FuncCode funcCode = FuncCode.FORCE_MULTIPLE_COILS;
        ReqMbData reqMbData = new ForceMultiCoilsReqMbData(startAddr, coilStatuses);
        return getReqMbFrm(seq, addr, funcCode, reqMbData);
    }

    /**
     * 构建请求格式帧 - 设置多个寄存器
     *
     * @param seq：序列号
     * @param addr：从站地址
     * @param startAddr：起始地址
     * @param setVals：值列表
     * @return
     */
    public static ReqMbFrm getReqMbFrmOfForceMultiRegs(int seq, int addr, int startAddr, List<Integer> setVals) {
        FuncCode funcCode = FuncCode.FORCE_MULTIPLE_REGISTERS;
        ReqMbData reqMbData = new ForceMultiRegsReqMbData(startAddr, setVals);
        return getReqMbFrm(seq, addr, funcCode, reqMbData);
    }
}
